﻿using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
/*CLR Version: 4.0.30319.18063
* Creat Date: 2015/3/16 13:47:09
* Creat Year: 2015
 * Creator: 程炜.Snail
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;

using System.Text.RegularExpressions;
namespace Utility.Extensions
{
    /// <summary>
    /// 基类型<see cref="Object"/>扩展辅助操作类
    /// </summary>
    public static class ObjectExtensions
    {
        private class NullToEmptyStringResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
        {
            protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
            {
                return type.GetProperties()
                        .Select(p => {
                            var jp = base.CreateProperty(p, memberSerialization);
                            jp.ValueProvider = new NullToEmptyStringValueProvider(p);
                            return jp;
                        }).ToList();
            }
        }
        private class NullToEmptyStringValueProvider : IValueProvider
        {
            PropertyInfo _MemberInfo;
            public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
            {
                _MemberInfo = memberInfo;
            }
            public object GetValue(object target)
            {
                object result = _MemberInfo.GetValue(target, null);
                if (_MemberInfo.PropertyType == typeof(string) && result == null)
                {
                    result = "";
                }
                return result;
            }

            public void SetValue(object target, object value)
            {
                _MemberInfo.SetValue(target, value, null);
            }
        }

        #region 公共方法
        /// <summary>
        /// 使用 Newtonsoft.Json.JsonConvert 序列化 对象 为 json 字符串数据
        /// </summary>
        /// <param name="value"></param>
        /// <param name="timeFormat">时间格式</param>
        /// <param name="clearEnter">清除回车符</param>
        /// <param name="nullToEmpty">是否将空字符串转换成""</param>
        /// <returns></returns>
        public static string ToJsonString(this object value, string timeFormat = "yyyy-MM-dd HH:mm:ss", bool clearEnter = true,bool nullToEmpty=true)
        {
            if (string.IsNullOrEmpty(timeFormat))
            {
                return Newtonsoft.Json.JsonConvert.SerializeObject(value);
            }
            Formatting format = Formatting.None;
            if (!clearEnter) //控制是否需要制表符
            {
                format = Formatting.Indented;
            }
            if (nullToEmpty)
            {
                var settings = new JsonSerializerSettings() { ContractResolver = new NullToEmptyStringResolver() };
                settings.Converters.Add(GetTimeConverter(timeFormat));

                var returnStr = Newtonsoft.Json.JsonConvert.SerializeObject(value, format, settings);
                return returnStr;
            }
            else
            {
                var returnStr = Newtonsoft.Json.JsonConvert.SerializeObject(value, format, GetTimeConverter(timeFormat));
                return returnStr;
            }
        }
        /// <summary>
        /// 根据 timeFormat 创建 IsoDateTimeConverter 对象
        /// </summary>
        /// <param name="timeFormat"></param>
        /// <returns></returns>
        private static Newtonsoft.Json.Converters.IsoDateTimeConverter GetTimeConverter(string timeFormat)
        {
            Newtonsoft.Json.Converters.IsoDateTimeConverter timeConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter();
            string timeformat = string.Empty;
            foreach (char c in timeFormat)
            {
                if ("YMDHSFymdhsf".IndexOf(c) < 0) //非日期时间的占位符,需要用 ''包含起来
                {
                    timeformat += string.Format("'{0}'", c);
                }
                else
                {
                    timeformat += c;
                }
            }
            timeConverter.DateTimeFormat = timeformat;
            return timeConverter;
        }
        /// <summary>
        /// 反序列
        /// </summary>
        /// <param name="value"></param>
        /// <param name="timeFormat"></param>
        /// <returns></returns>
        public static T FromJsonString<T>(this string value, string timeFormat = "yyyy-MM-dd HH:mm:ss")
        {
            try
            {
                if (string.IsNullOrEmpty(timeFormat))
                {
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(value);                    
                }
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(value, GetTimeConverter(timeFormat));
            }
            catch (Exception ex)
            { }
            return default(T);
        }
        /// <summary>
        /// 序列号成指定类型,以Object方式返回
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <param name="timeFormat"></param>
        /// <returns></returns>
        public static object FromJsonString(this string value, Type type, string timeFormat = "yyyy-MM-dd HH:mm:ss")
        {
            try
            {
                if (string.IsNullOrEmpty(timeFormat))
                {
                    return Newtonsoft.Json.JsonConvert.DeserializeObject(value, type);
                }
                return Newtonsoft.Json.JsonConvert.DeserializeObject(value, type, GetTimeConverter(timeFormat));
            }
            catch (Exception ex)
            { }
            return null;
        }
        /// <summary>
        /// 根据指定Json的属性名称获取对应属性的值
        /// </summary>
        /// <param name="value"></param>
        /// <param name="objectKey">指定的Json中Key</param>
        /// <returns></returns>
        public static string JsonStringParse(this string value,string objectKey)
        {
            if (string.IsNullOrEmpty(objectKey))
            {
                return string.Empty;
            }
            try
            {
                Newtonsoft.Json.Linq.JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(value);
                if (null != jObject)
                {
                    return jObject[objectKey].ToString();
                }
            }
            catch (Exception ex)
            { }
            return string.Empty;
        }
        /// <summary>
        /// 把对象类型转换为指定类型
        /// </summary>
        /// <param name="value"></param>
        /// <param name="conversionType"></param>
        /// <returns></returns>
        public static object CastTo(this object value, Type conversionType)
        {
            if (value == null)
            {
                return null;
            }
            if (conversionType.IsNullableType())
            {
                conversionType = conversionType.GetUnNullableType();
            }
            if (conversionType.IsEnum)
            {
                return Enum.Parse(conversionType, value.ToString());
            }
            if (conversionType == typeof(Guid))
            {
                return Guid.Parse(value.ToString());
            }
            return Convert.ChangeType(value, conversionType);
        }

        /// <summary>
        /// 把对象类型转化为指定类型
        /// </summary>
        /// <typeparam name="T"> 动态类型 </typeparam>
        /// <param name="value"> 要转化的源对象 </param>
        /// <returns> 转化后的指定类型的对象，转化失败引发异常。 </returns>
        public static T CastTo<T>(this object value)
        {
            object result = CastTo(value, typeof(T));
            return (T)result;
        }

        /// <summary>
        /// 把对象类型转化为指定类型，转化失败时返回指定的默认值
        /// </summary>
        /// <typeparam name="T"> 动态类型 </typeparam>
        /// <param name="value"> 要转化的源对象 </param>
        /// <param name="defaultValue"> 转化失败返回的指定默认值 </param>
        /// <returns> 转化后的指定类型对象，转化失败时返回指定的默认值 </returns>
        public static T CastTo<T>(this object value, T defaultValue)
        {
            try
            {
                return CastTo<T>(value);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }
        /// <summary>
        /// 将字节数组转换成Base64文字
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToBase64String(this byte[] value)
        {
            return Convert.ToBase64String(value);
        }
        /// <summary>
        /// 将字节数组文字转换成字节
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static byte[] FromBase64String4Byte(this string value)
        {
            return Convert.FromBase64String(value);
        }
        /// <summary>
        /// 判断当前值是否介于指定范围内
        /// </summary>
        /// <typeparam name="T"> 动态类型 </typeparam>
        /// <param name="value"> 动态类型对象 </param>
        /// <param name="start"> 范围起点 </param>
        /// <param name="end"> 范围终点 </param>
        /// <param name="leftEqual"> 是否可等于上限（默认等于） </param>
        /// <param name="rightEqual"> 是否可等于下限（默认等于） </param>
        /// <returns> 是否介于 </returns>
        public static bool IsBetween<T>(this IComparable<T> value, T start, T end, bool leftEqual = false, bool rightEqual = false) where T : IComparable
        {
            bool flag = leftEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0;
            return flag && (rightEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0);
        }
        /// <summary>
        /// 根据属性名称获取值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static object GetPropertyValue<T>(this T obj, string name)
        {
            PropertyInfo[] properties = typeof(T).GetProperties();
            foreach (PropertyInfo property in properties)
            {
                if (property.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
                {
                    return property.GetValue(obj, null);
                }
            }
            return null;
        }
        /// <summary>
        /// 复制一个对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T Clone<T>(this T obj) where T : new()
        {
            if (null == obj)
            {
                return default(T);
            }
            Type objTye = typeof(T);
            T model = new T();
            
            PropertyInfo[] properties = objTye.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                if (!property.IsSpecialName && property.CanWrite)
                {
                    object o = property.GetValue(obj, null);
                    if (null != o)
                    {
                        property.SetValue(model, o, null);
                    }
                }
            }
            return model;
        }
        /// <summary>
        /// 通过实例的所有公共属性比较两个对象是否相同
        /// </summary>
        /// <typeparam name="TempClass"></typeparam>
        /// <param name="obj1"></param>
        /// <param name="obj2"></param>
        /// <returns></returns>
        public static bool Equals<TempClass>(this TempClass obj1, TempClass obj2)
        {
            Type type1 = obj1.GetType();
            Type type2 = obj2.GetType();

            System.Reflection.PropertyInfo[] properties1 = type1.GetProperties();
            System.Reflection.PropertyInfo[] properties2 = type2.GetProperties();

            bool IsMatch = true;
            for (int i = 0; i < properties1.Length; i++)
            {
                string s = properties1[i].DeclaringType.Name;
                if (!"NewKey".Equals(properties1[i].Name, StringComparison.OrdinalIgnoreCase) && (properties1[i].GetValue(obj1, null).ToString() != properties2[i].GetValue(obj2, null).ToString()))
                {
                    IsMatch = false;
                    break;
                }
            }
            return IsMatch;
        }
        /// <summary>
        ///  判断两个值或对象是否相同
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="oldObj"></param>
        /// <param name="newObj"></param>
        /// <returns></returns>
        public static bool IsEqual(Type dataType, object oldObj, object newObj)
        {
            if (oldObj == null && newObj == null)
                return true;

            if (dataType == typeof(int))
            {
                return (int)oldObj == (int)newObj;
            }
            else if (dataType == typeof(decimal))
            {
                return (decimal)oldObj == (decimal)newObj;
            }
            else if (dataType == typeof(double))
            {
                return (double)oldObj == (double)newObj;
            }
            else if (dataType == typeof(Guid))
            {
                return (Guid)oldObj == (Guid)newObj;
            }
            else if (dataType == typeof(DateTime))
            {
                return (DateTime)oldObj == (DateTime)newObj;
            }
            else
                return oldObj.Equals(newObj);

        }        
        #endregion
    }
}